/*  Game/Army Editor for yALB - Yet Another List Builder (roster Editor for Wargames/tabletop games).
    Copyright (C) 2008-2012  Daniel Ricardo Castro Alvarado

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.*/

#include "unitwidget.h"
#include "ui_unitwidget.h"

#include "other/functions.h"

#include <QDebug>
#include <QMessageBox>
#include <QSet>

// \FIXME: Fix signals

UnitWidget::UnitWidget(const UnitCollection &_units, ItemSelector &_itemSelector,
                       CategoryLimitDialog& _categoryDialog, QWidget *parent) :
    QWidget(parent),
    ui(new Ui::UnitWidget), optionForm(_itemSelector)
{
    ui->setupUi(this);
    units = &_units;
    itemSelector = &_itemSelector;
    categoryDialog = &_categoryDialog;

    connect(this, SIGNAL(addUnitRequested(Unit,QString)),
            units, SLOT(add(Unit,QString)));
    connect(this, SIGNAL(updateUnitRequested(QString,Unit,QString)),
            units, SLOT(update(QString,Unit,QString)));
    connect(this, SIGNAL(removeUnitRequested(QString)), units,
            SLOT(remove(QString)));

    connect(units, SIGNAL(unitAdded(Unit,QString)), this,
            SLOT(addUnit(Unit,QString)));
    connect(units, SIGNAL(unitUpdated(QString,Unit,QString)),
            this, SLOT(updateUnit(QString,Unit,QString)));
    connect(units, SIGNAL(unitRemoved(QString)), this,
            SLOT(removeUnit(QString)));

    connect(units, SIGNAL(cleared()), this, SLOT(clearAll()));

    ui->unitTree->header()->resizeSection(1, 50);
    ui->unitTree->setAlternatingRowColors(true);
}

UnitWidget::~UnitWidget()
{
    delete ui;
}

void UnitWidget::clearUnitForm() {
    ui->unitName->setText("");
    ui->unitID->setText("");
    ui->unitDescription->setPlainText("");
    ui->unitIsHidden->setChecked(false);
    ui->unitUsesParentSize->setChecked(false);
    ui->unitMinSize->setValue(1);
    ui->unitMaxSize->setValue(0);
    currentLimits.clear();
    ui->unitAllowedItems->setText("");
}

QList<KeyPair<Unit> > UnitWidget::getOrderedUnits() {
    QList<KeyPair<Unit> > list;

    for(int i = 0; i<ui->unitTree->topLevelItemCount(); ++i) {
        QTreeWidgetItem *categoryItem = ui->unitTree->topLevelItem(i);
        for(int a = 0; a<categoryItem->childCount(); ++a) {
            QString key = categoryItem->child(a)->data(0, Qt::UserRole).toString();
            list.append(KeyPair<Unit>(key, units->get(key)));
        }
    }

    return list;
}

void UnitWidget::addUnit(const Unit &unit, const QString &key) {
    Q_ASSERT_X(!keyIndex.contains(key), "UnitWidget::addUnit()", "Attempting to replace existing element");
    QTreeWidgetItem *item = new QTreeWidgetItem(QStringList(unit.getName()));
    item->setData(0, Qt::UserRole, key);

    int index = 0; // Default to "No Category"
    if(!unit.category.isEmpty()) {
        for(int i = 1; i<ui->unitTree->topLevelItemCount(); ++i) {
            if (ui->unitTree->topLevelItem(i)->data(0, Qt::UserRole).toString() == unit.category) {
                index = i;
                break;
            }
        }
    }
    item->setFlags(item->flags() | Qt::ItemIsEditable);

    // Set up cells

    item->setText(1, QString::number(unit.getCost()));

    QStringList cellKeys = unit.cells.keys();
    for(int i=0; i<cellKeys.count(); ++i) {
        int column = columnIndex.value(cellKeys.at(i), -1);
        if(column > -1)
            item->setText(column, unit.cells.value(cellKeys.at(i)));
    }

    ui->unitTree->topLevelItem(index)->addChild(item);
    ui->unitTree->expandItem(ui->unitTree->topLevelItem(index));

    keyIndex.insert(key, item);

    clearUnitForm();
}

void UnitWidget::updateUnit(const QString& oldKey, const Unit& newUnit,
                const QString& newKey) {
    QTreeWidgetItem *item = keyIndex.value(oldKey, NULL);
    if(item) {
        if(oldKey != newKey) {
            Q_ASSERT_X(!keyIndex.contains(newKey), "UnitWidget::addUnit()", "Attempting to replace existing element");
            item->setData(0, Qt::UserRole, QVariant(newKey));
            keyIndex.remove(oldKey);
            keyIndex.insert(newKey, item);
        }
        item->setText(0, newUnit.getName());
        int indexOfParent = ui->unitTree->indexOfTopLevelItem(item->parent());
        int indexNewParent = 0;

        if (!newUnit.category.isEmpty()) {
            for(int i = 1; i<ui->unitTree->topLevelItemCount(); ++i) {
                if (ui->unitTree->topLevelItem(i)->data(0, Qt::UserRole).toString() == newUnit.category) {
                    indexNewParent = i;
                    break;
                }
            }
        }

        item->setText(1, QString::number(newUnit.getCost()));

        QStringList cellKeys = newUnit.cells.keys();
        for(int i=0; i<cellKeys.count(); ++i) {
            int column = columnIndex.value(cellKeys.at(i), -1);
            if(column > -1)
                item->setText(column, newUnit.cells.value(cellKeys.at(i)));
        }

        if (indexOfParent != indexNewParent) {
            ui->unitTree->topLevelItem(indexOfParent)->removeChild(item);
            ui->unitTree->topLevelItem(indexNewParent)->addChild(item);
            ui->unitTree->expandItem(item->parent());
            ui->unitTree->setCurrentItem(item);
        }

    }
}

void UnitWidget::removeUnit(const QString& key) {
    QTreeWidgetItem *item = keyIndex.value(key, NULL);
    if(item) {
        delete item;
        keyIndex.remove(key);
    }
}

void UnitWidget::addUnitCategory(const GameCategory &category, const QString &key) {
    QTreeWidgetItem *item = new QTreeWidgetItem(ui->unitTree, QStringList(category.getName()));
    item->setData(0, Qt::UserRole, key);
    ui->unitCategory->addItem(category.getName(), key);

    QTreeWidgetItem *noCategory = ui->unitTree->topLevelItem(0);

    // Check if there are items with the new category key
    QTreeWidgetItem *child;
    for(int i = noCategory->childCount() -1; i>=0; --i) {
        child = noCategory->child(i);
        Unit unit(units->get(child->data(0, Qt::UserRole).toString()));
        if(unit.category == key) {
            noCategory->removeChild(child);
            item->addChild(child);
        }
    }
}

void UnitWidget::updateUnitCategory(const QString& oldKey, const GameCategory& newCategory,
                     const QString& newKey) {
    for(int i = 1; i<ui->unitTree->topLevelItemCount(); ++i) {
        QTreeWidgetItem *item = ui->unitTree->topLevelItem(i);
        if(item->data(0, Qt::UserRole).toString() == oldKey) {
            item->setText(0, newCategory.getName());
            ui->unitCategory->setItemText(i, newCategory.getName());

            if(oldKey != newKey) {
                item->setData(0, Qt::UserRole, QVariant(newKey));
                ui->unitCategory->setItemData(i, QVariant(newKey));

                int optionCount = item->childCount(); // Options in this category
                QTreeWidgetItem *noCategory = ui->unitTree->topLevelItem(0);

                // Move items in this category to "No category"
                Functions::moveChildrenToRow(item, noCategory);

                // Check if there are items with the new category key
                QTreeWidgetItem *child;
                for(int a = noCategory->childCount() - optionCount -1; a>=0; --a) {
                    child = noCategory->child(a);
                    Unit unit(units->get(child->data(0, Qt::UserRole).toString()));
                    if(unit.category == newKey) {
                        noCategory->removeChild(child);
                        item->addChild(child);
                    }
                }
            }
            break;
        }
    }
}

void UnitWidget::removeUnitCategory(const QString& key) {
    for(int i = 1; i<ui->unitTree->topLevelItemCount(); ++i) {
        QTreeWidgetItem *item = ui->unitTree->topLevelItem(i);
        if(item->data(0, Qt::UserRole).toString() == key) {
            // Move items in this category to "No category"
            Functions::moveChildrenToRow(item, ui->unitTree->topLevelItem(0));
            delete item;
            ui->unitCategory->removeItem(i);
            break;
        }
    }
}

void UnitWidget::addColumn(const Column &column, const QString &key) {
    Q_ASSERT(!columnIndex.contains(key));

    QTreeWidgetItem *header = ui->unitTree->headerItem();
    int columnNumber = header->columnCount();
    header->setText(columnNumber, column.getName());
    header->setData(columnNumber, Qt::UserRole, QVariant(key));
    ui->unitTree->header()->setResizeMode(columnNumber, QHeaderView::Stretch);
    columnIndex.insert(key, columnNumber);
}

void UnitWidget::updateColumn(const QString& oldKey, const Column& newColumn,
                     const QString& newKey) {
    Q_ASSERT(columnIndex.contains(oldKey));

    int column = columnIndex.value(oldKey);

    QTreeWidgetItem *header = ui->unitTree->headerItem();
    header->setText(column, newColumn.getName());
    if(oldKey != newKey) {
        Q_ASSERT(!columnIndex.contains(newKey));
        columnIndex.insert(newKey, column);
        columnIndex.remove(oldKey);
        header->setData(column, Qt::UserRole, QVariant(newKey));
    }
}

void UnitWidget::removeColumn(const QString& key) {
    Q_ASSERT(columnIndex.contains(key));

    int columnToRemove = columnIndex.value(key);
    columnIndex.clear();

    QTreeWidgetItem *newHeader = new QTreeWidgetItem();
    QTreeWidgetItem *oldHeader = ui->unitTree->headerItem();

    for(int i = 0; i<oldHeader->columnCount(); ++i) {
        if(i == columnToRemove)
            continue;
        int columnNumber = newHeader->columnCount();
        newHeader->setText(columnNumber, oldHeader->text(i));
        newHeader->setData(columnNumber, Qt::UserRole, oldHeader->data(i, Qt::UserRole));
        columnIndex.insert(oldHeader->data(i, Qt::UserRole).toString(), columnNumber);
    }

    ui->unitTree->setHeaderItem(newHeader);
}

void UnitWidget::clearAll() {
    qDeleteAll(ui->unitTree->topLevelItem(0)->takeChildren());
    for(int i = ui->unitTree->topLevelItemCount() -1; i>=1; --i) {
        qDeleteAll(ui->unitTree->topLevelItem(i)->takeChildren());
    }
    keyIndex.clear();
    clearUnitForm();
}

void UnitWidget::clearAllColumns() {
    columnIndex.clear();
    ui->unitTree->setColumnCount(2);
}

void UnitWidget::clearAllCategories() {
    for(int i = ui->unitTree->topLevelItemCount() -1; i>=1; --i) {
        Functions::moveChildrenToRow(ui->unitTree->topLevelItem(i), ui->unitTree->topLevelItem(0));
        delete ui->unitTree->topLevelItem(i);
        ui->unitCategory->removeItem(i);
    }
    optionForm.clearAllCategories();
}

void UnitWidget::clearAllProperties() {
    propertyForm.clearAll();
    optionForm.clearAllProperties();
}

void UnitWidget::on_unitTree_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
{
    Q_UNUSED(previous)
    propertyForm.clearAllValues();
    propertyForm.savePropertyValues();
    if(current && current->parent()) {
        QString key = current->data(0, Qt::UserRole).toString();
        if(units->contains(key)) {
            const Unit &unit = units->get(key);

            int categoryIndex = ui->unitCategory->findData(QVariant(unit.category));
            categoryIndex = categoryIndex > -1 && categoryIndex < ui->unitCategory->count() ? categoryIndex : 0;

            ui->unitCategory->setCurrentIndex(categoryIndex);
            ui->unitName->setText(unit.getName());
            ui->unitID->setText(key);
            ui->unitDescription->setPlainText(unit.description);
            ui->unitIsHidden->setChecked(unit.flags.testFlag(Unit::Hidden));
            ui->unitUsesParentSize->setChecked(unit.flags.testFlag(Unit::UsesParentSize));
            ui->unitMinSize->setValue(unit.getMinimumSize());
            ui->unitMaxSize->setValue(unit.getMaximumSize());
            currentLimits = unit.itemLimits;
            ui->unitAllowedItems->setText(unit.allowedItems.join(","));


            ui->unitDelete->setEnabled(true);
            ui->unitUpdate->setEnabled(true);
            ui->unitClone->setEnabled(true);
            ui->unitMoveUp->setEnabled(true);
            ui->unitMoveDown->setEnabled(true);

            QHash<QString, QString>::const_iterator i;
            for(i = unit.properties.constBegin();
                i != unit.properties.constEnd(); ++i)
                propertyForm.setPropertyValue(i.key(), i.value());

            ui->unitGroupBox->setEnabled(true);

        } else {
            qDebug() << "This ID does not exist in units";
            clearUnitForm();
            ui->unitDelete->setEnabled(false);
            ui->unitUpdate->setEnabled(false);
            ui->unitClone->setEnabled(false);
            ui->unitMoveUp->setEnabled(false);
            ui->unitMoveDown->setEnabled(false);

            int categoryIndex = ui->unitTree->indexOfTopLevelItem(current->parent());
            categoryIndex = categoryIndex > -1 && categoryIndex < ui->unitCategory->count() ? categoryIndex : 0;

            ui->unitCategory->setCurrentIndex(categoryIndex);
            ui->unitGroupBox->setEnabled(false);
        }
    } else {
        clearUnitForm();
        ui->unitDelete->setEnabled(false);
        ui->unitUpdate->setEnabled(false);
        ui->unitClone->setEnabled(false);
        ui->unitMoveUp->setEnabled(false);
        ui->unitMoveDown->setEnabled(false);

        int categoryIndex = ui->unitTree->indexOfTopLevelItem(current);
        categoryIndex = categoryIndex > -1 && categoryIndex < ui->unitCategory->count() ? categoryIndex : 0;

        ui->unitCategory->setCurrentIndex(categoryIndex);

        ui->unitGroupBox->setEnabled(false);
    }
}

void UnitWidget::on_unitAdd_clicked()
{
    Unit::UnitFlags flags;
    if(ui->unitIsHidden->isChecked())
        flags |= Unit::Hidden;
    if(ui->unitUsesParentSize->isChecked())
        flags |= Unit::UsesParentSize;
    Unit unit(ui->unitCategory->itemData(ui->unitCategory->currentIndex()).toString(),
              ui->unitName->text(), ui->unitDescription->toPlainText(), 0.0, flags,
              ui->unitMinSize->value(), ui->unitMaxSize->value(), currentLimits,
              ui->unitAllowedItems->text().split(',',QString::SkipEmptyParts),
              QHash<QString, QString>(), OptionCollection(), QHash<QString,QString>());
    QString key = ui->unitID->text();
    emit addUnitRequested(unit, key);
}

void UnitWidget::on_unitUpdate_clicked()
{
    Unit::UnitFlags flags;
    if(ui->unitIsHidden->isChecked())
        flags |= Unit::Hidden;
    if(ui->unitUsesParentSize->isChecked())
        flags |= Unit::UsesParentSize;
    QString key = ui->unitTree->currentItem()->data(0, Qt::UserRole).toString();
    Unit oldUnit = units->get(key);
    Unit newUnit(ui->unitCategory->itemData(ui->unitCategory->currentIndex()).toString(),
                 ui->unitName->text(), ui->unitDescription->toPlainText(), 0.0, flags,
                 ui->unitMinSize->value(), ui->unitMaxSize->value(), currentLimits,
                 ui->unitAllowedItems->text().split(',',QString::SkipEmptyParts),
                 oldUnit.properties, oldUnit.options, oldUnit.cells);
    emit updateUnitRequested(key, newUnit, ui->unitID->text());
}

void UnitWidget::on_unitDelete_clicked()
{
    if(QMessageBox::warning(0, tr("Are you sure?"), tr("Deleting a unit will make invalid all values that use it. Are you sure you want to continue?"),
                            QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes)
        emit removeUnitRequested(ui->unitTree->currentItem()->data(0, Qt::UserRole).toString());
}

void UnitWidget::on_unitClone_clicked()
{
    QTreeWidgetItem* item = ui->unitTree->currentItem();
    if (item && item->parent()) {
        QString oldKey = item->data(0, Qt::UserRole).toString();
        QString newKey;
        Unit oldUnit(units->get(oldKey));
        Unit unit(oldUnit);

        int i = 0;

        bool valid = false;
        do {

            newKey = QString("%1_%2").arg(oldKey, QString::number(i));
            unit.setName(QString("%1_%2").arg(oldUnit.getName(), QString::number(i)));
            if(!GameStructs::isValidKey(newKey)) // Prevent the app to fall in an infinite loop
                break;
            valid = !units->contains(newKey);
            ++i;
        } while (valid == false);
        if(valid) {
            emit addUnitRequested(unit, newKey);
        }
    }
}

void UnitWidget::on_unitSetItems_clicked()
{
    ui->unitAllowedItems->setText(
                itemSelector->getStringFromSelectedItems(ui->unitAllowedItems->text()));
}

void UnitWidget::on_unitSetProperties_clicked()
{
    QString key = ui->unitTree->currentItem()->data(0, Qt::UserRole).toString();
    if(!key.isEmpty() && propertyForm.exec() == QDialog::Accepted) {
        Unit unit(units->get(key));
        unit.properties = propertyForm.getProperties();
        emit updateUnitRequested(key, unit, key);
    }
}

void UnitWidget::on_unitSetOptions_clicked()
{
    QString key = ui->unitTree->currentItem()->data(0, Qt::UserRole).toString();
    if(!key.isEmpty()) {
        Unit unit(units->get(key));
        unit.options = optionForm.getUnitOptions(unit.options);
        emit updateUnitRequested(key, unit, key);
    }
}

void UnitWidget::on_unitTree_userChangedText(QTreeWidgetItem *item, int column)
{
    if(item && item->parent()) {
        QString key = item->data(0, Qt::UserRole).toString();
        if(units->contains(key)) {
            Unit unit = units->get(key);
            switch(column) {
            case 0: // Modifiyng "Name" column
                unit.setName(item->text(0));
                break;
            case 1: { // Modifying "Cost" column
                unit.setCost(item->text(1).toFloat());
                break;
            } default:
                unit.cells.insert(ui->unitTree->headerItem()->data(column, Qt::UserRole).toString(),
                                  item->text(column));
            }
            emit updateUnitRequested(key, unit, key);
        }
    }
}

void UnitWidget::on_unitMoveUp_clicked()
{
    int index = ui->unitTree->currentIndex().row();

    QTreeWidgetItem *item = ui->unitTree->currentItem();
    QTreeWidgetItem *parent = item->parent();

    parent->takeChild(index);
    if(index > 0)
        parent->insertChild(index-1, item);
    else
        parent->addChild(item);
    ui->unitTree->setCurrentItem(item);
}

void UnitWidget::on_unitMoveDown_clicked()
{
    int index = ui->unitTree->currentIndex().row();

    QTreeWidgetItem *item = ui->unitTree->currentItem();
    QTreeWidgetItem *parent = item->parent();

    parent->takeChild(index);
    if(index < parent->childCount())
        parent->insertChild(index+1, item);
    else
        parent->insertChild(0, item);
    ui->unitTree->setCurrentItem(item);
}

void UnitWidget::on_unitItemLimitsButton_clicked()
{
    currentLimits = categoryDialog->getItemLimits(currentLimits);
}

void UnitWidget::changeEvent(QEvent *event) {
    if(event->type() == QEvent::LanguageChange)
        ui->retranslateUi(this);
    QWidget::changeEvent(event);
}
